// file:arch/x86/include/arch/interrupt.h
// autor:jiangxinpeng
// time:2021.1.15
// copyright:(C) 2020-2050 by jiangxinpeng,All right are reserved.

#ifndef X86_INTERRUPT_H
#define X86_INTERRUPT_H

#include <lib/type.h>
#include <arch/atomic.h>
#include <arch/x86.h>

#define IRQ0_CLOCK 0     // clock
#define IRQ1_KEYBOARD 1  // keyboard
#define IRQ2_SLAVE 2     // connect slave chips
#define IRQ3_SERIAL2 3   // serial 2: com 2/com 4
#define IRQ4_SERIAL1 4   // serial 1: com 1/com 3
#define IRQ5_PARALLEL2 5 // LPT 2
#define IRQ6_FLOPPY 6    // floppy
#define IRQ7_PARALLEL1 7 // LPT 1

#define IRQ8_RTC 8         // RTC
#define IRQ9_MASTER 9      // connect master chips
#define IRQ10_RESERVED 10  // reserved
#define IRQ11_RESERVED 11  // reserved
#define IRQ12_MOUSE 12     // mouse
#define IRQ13_FPU 13       // fpu
#define IRQ14_HARDDISK1 14 // harddisk 1
#define IRQ15_HARDDISK2 15 // harddisk 2

#define INTERRUPT_NUM_MAX 256 // max 256 interrupt
#define HARDIRQ_MAX 32 

#define INTELOFF 0x0 // intel reserved exception vector offset in IDT
#define IRQOFF1 0x20 // master irq offset in IDT
#define IRQOFF2 0x28 // slave irq offset in IDT
#define USEROFF 0x80 // system  interrupt offset in IDT

#define IRQ_HANDLER_SIZE 0x2E // irq hanler size

typedef enum
{
    EP_DIV = 0,                   // div error: div or idiv instruction
    EP_DEBUG,                     // debug except: any software or data
    EP_NMI,                       // NMI: no-mask extern interrupt
    EP_BREAKPOINT,                // debug breakpoint: int3 instruction
    EP_OVERFLOW,                  // overflow: into instructoin
    EP_BOUND_RANGE,               // bound range: bount instruction
    EP_INVALID_OPCODE,            // unused or undefine opcode: ud2 instruction or unused instruction
    EP_NO_DEVICE_AVAILABLE,       // device unused (no FPU): float or wait/fwait instruction
    EP_DOUBLE_ERROR,              // double error: any can generation exception,NMI,INTR instruction
    EP_COPROCESSOR_SEGMENT_BOUND, // coprocessor segment bound: float instruction(arch86 cpu x86 arch no again generation)
    EP_INVALID_TSS,               // invalid tss: task switch or access tss
    EP_SEGMENT_NOT_PRESENT,       // segment not present: load segmeng register or access segment
    EP_STACK_ERROR,               // stack error: load ss register or access stack
    EP_GENERAL_PROTECT,           // general protect: mem or other protect check
    EP_PAGE_FAULT,                // page fault: mem access
    EP_RESERVED0,                 // intel reserved: unused
    EP_X87_FLOATPOINT,            // x87 float error(math error): x87 float instruction or wait/fwait instruction
    EP_ALIGN_CHECK,               // align check: mem data access
    EP_MACHINE_CHECK,             // machine check: error code and source depend on specific mode(pentium CPU start support)
    EP_SIMD_FLOATPOINT,           // SIMD float point exception: SSE and SSE2 instruction(pentium III start support)
    EP_RESERVED1,                 // reserved
    EP_RESERVED2,                 // reserved
} exception_type_t;

#pragma pack(push, 1)
typedef struct trap_frame
{
    uint32_t vec_num; // vector number
    uint32_t edi;
    uint32_t esi;
    uint32_t ebp;
    uint32_t esp_dump;
    uint32_t ebx;
    uint32_t edx;
    uint32_t ecx;
    uint32_t eax;
    uint32_t gs;
    uint32_t fs;
    uint32_t es;
    uint32_t ds;
    uint32_t error_code; // error code
    uint32_t eip;
    uint32_t cs;
    uint32_t eflags;
    // if CPL change,we need push ss and esp
    uint32_t esp;
    uint32_t ss;
} trap_frame_t;
#pragma pack(pop)

typedef void (*interrupt_handler_t)();
typedef char *interrupt_name_t;

#define ERROR_CODE_EXT (1 << 0)
#define ERROR_CODE_IDT (1 << 1)
#define ERROR_CODE_TI (1 << 2)
#define ERROR_CODE_SEL_MASK(code) ((code) >> 3 & 0xffff)

// mange all interrupt
typedef struct interrupt
{
    interrupt_name_t name;
    interrupt_handler_t function;
} interrupt_t;

extern interrupt_t interrupt[INTERRUPT_NUM_MAX];

#define InterruptDisable() DisInterrupt()
#define InterruptEnable() EnInterrupt()

__attribute((optimize("O0"))) static inline uint32_t InterruptDisableStore()
{
    uint32_t eflags=StoreEflag();
    InterruptDisable();
    return eflags;
}

__attribute((optimize("O0"))) static inline void InterruptEnableRestore(uint32_t eflags)
{
    InterruptEnable();
    LoadEflag(eflags);
}

uint8_t IntVectorAlloc();
void IntVectorFree(uint8_t vec);

void InterruptRegister(uint32_t interrrupt_index, interrupt_handler_t function);
void InterruptUnRegister(uint32_t interrupt_index);

void InterruptExceptionInit();
void InterruptInit();

__attribute((optimize("O0"))) void InterruptGeneralHandler(uint32_t esp);
__attribute((optimize("O0"))) void DumpTrapFrame(trap_frame_t *frame);

int __attribute__((optimize("O0"))) InterruptDoIrq(trap_frame_t *frame);

void IrqUnRegisterInterrupt(uint32_t irq);
void IrqRegisterInterrupt(uint32_t irq, interrupt_handler_t function);

extern void InterruptExit();
#endif